//timewheel.cpp使用析构函数和指针指针实现我们的时间轮定时任务的实现

#include <iostream>
#include <vector>
#include <unordered_map>
#include <cstdint>
#include <functional>
#include <memory>
#include <unistd.h>

using TaskFunc=std::function<void()>;  //使用TaskFunc包装器函数
using ReleaseFunc=std::function<void()>; //额外的释放操作

//我们将我们的定时任务封装为一个类，便于析构函数调用我们的定时任务
class TimerTask{
    private:
        uint64_t _id; //定时器任务的id
        uint32_t _timeout; //这是定时任务的超时时间
        bool _canceled; //是否取消任务 false没有取消 true取消
        TaskFunc _task_cb; //定时器要执行的定时任务
        ReleaseFunc _release; //用于删除TimerWheel中保存的定时器对象信息
    
    public:
        //定时器的构造，定时器id，延迟时间，要执行的定时任务
        TimerTask(uint64_t id,uint32_t delay,const TaskFunc &cb) 
            :_id(id),_timeout(delay),_task_cb(cb),_canceled(false) {}

        //定时器的析构，并且执行我们的定时任务
        ~TimerTask() 
        {
            if(_canceled==false)_task_cb();
            _release();
        }

        void Cancel() {_canceled=true;} //取消我们的定时任务
        void SetRelease(const ReleaseFunc &cb) {_release=cb;}; //删除对应哈希表中的数据
        uint64_t DelayTime() {return _timeout;}; // 获取超时时间
};

//这是我们的时间轮的类，我们将定时任务类存放在时间轮中
class TimerWheel{
    private:
        using WeakTask=std::weak_ptr<TimerTask>; //weak_ptr
        using PtrTask=std::shared_ptr<TimerTask>; //声明一个智能指针类型
        //时间轮是一个二维数组，同一个时间可能有多个定时任务要执行
        int _tick; //释放tick处的对象，走到哪里执行哪里的任务
        int _capacity; //表盘的最大数量，就是最大的延迟时间
        std::vector<std::vector<PtrTask>> _wheel; //注意存放的是PtrTask
        std::unordered_map<uint64_t,WeakTask> _timers; //id和weak_ptr对象的映射
    private:
        //删除我们哈希表中id定时任务
        void RemoveTimer(uint64_t id)
        {
            auto it=_timers.find(id); //通过迭代器我们找到id的位置
            if(it!=_timers.end())
            {
                _timers.erase(it);
            }
        }

    public:
        //初始化我们的时间轮
        TimerWheel():_capacity(60),_tick(0),_wheel(_capacity){}
        
        //添加定时任务
        void TimerAdd(uint64_t id,uint32_t delay,const TaskFunc &cb)
        {
            PtrTask pt(new TimerTask(id,delay,cb)); //新建一个定时任务的智能指针类
            pt->SetRelease(std::bind(&TimerWheel::RemoveTimer,this,id)); //释放对象，要传入隐藏的this指针
            int pos=(_tick+delay)%_capacity; //取模
            _wheel[pos].push_back(pt); //添加到时间轮后的超时位置
            _timers[id]=WeakTask(pt); //针对ptr示例化一个weak_ptr
        }
        
        //刷新延时定时任务
        void TimeRefresh(uint64_t id) 
        {
            //通过保存的定时器对象的weak_ptr构造一个shared_ptr，添加到轮子中
            auto it=_timers.find(id); //通过迭代器我们找到id的位置
            if(it==_timers.end())
            {
                return ; //没有找到定时任务
            }

            PtrTask pt=it->second.lock(); //lock用来获取weak_ptr管理对象对应的shared_ptr
            int delay=pt->DelayTime(); //获取超时时间
            int pos=(_tick+delay)%_capacity; //取模
            _wheel[pos].push_back(pt); //添加到时间轮后的超时位置
        }

        //取消对应id的定时任务
        void TimerCancel(uint64_t id) 
        {
            auto it=_timers.find(id); //通过迭代器我们找到id的位置
            if(it==_timers.end())
            {
                return ; //没有找到定时任务
            }
            PtrTask pt=it->second.lock();
            if(pt) pt->Cancel();
        }

        //执行我们的定时任务，每秒进行一次
        void RunTimerTask()
        {
            _tick=(_tick+1)%_capacity;
            _wheel[_tick].clear(); //清空指定位置的数组，就会吧数组中所有管理定时器对象的share_ptr释放掉
        }
};

class Test
{
    public:
        Test() {std::cout<<"构造"<<std::endl;}
        ~Test() {std::cout<<"析构"<<std::endl;}
};

void DelTest(Test *t)
{
    delete t;
}

//进行时间轮的测试
int main()
{
    TimerWheel tw; //创建一个时间轮
    Test *t=new Test();
    tw.TimerAdd(888,5,std::bind(DelTest,t));
    for(int i=0;i<5;i++)
    {
        sleep(1);
        tw.TimeRefresh(888); //刷新定时任务
        tw.RunTimerTask(); //向后移动秒针
        std::cout<<"刷新了一下定时任务，重新需要5秒中后才会销毁\n";
    }
    tw.TimerCancel(888); //取消我们的定时任务
    while(1)
    {
        sleep(1);
        std::cout<<"--------------------\n";
        tw.RunTimerTask(); //向后移动秒针
    }
    return 0;
}